1 First step

The ALICIA - Concytec page was used to search for undergraduate theses with the following search strategy:

(“Análisis Factorial” OR “Análisis de Componentes Principales” OR “ACP” OR “confiabilidad” OR “fiabilidad” OR “análisis psicométrico” OR “baremación”) OR ((“validez” OR “validación” OR “adaptación” OR “construcción” OR “estandarización”) AND (“escala” OR “batería de pruebas” OR “prueba psicológica” OR “instrumento” OR “cuestionario” OR “test”))

In addition, the following filters were used:

  • Year from 2011 to 2020
  • Undergraduate thesis
  • Open Access thesis

All this is kept in a static link that will be used to inspect and store the data in an excel file.

library(rvest)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ──────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.3     ✓ purrr   0.3.4
✓ tibble  3.1.2     ✓ dplyr   1.0.6
✓ tidyr   1.1.3     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
── Conflicts ─────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter()         masks stats::filter()
x readr::guess_encoding() masks rvest::guess_encoding()
x dplyr::lag()            masks stats::lag()

1.1 Determinate the number of pages

last_n_page <- dina_html %>% 
  html_elements(".pagination li:last-child") %>% 
  html_text2() %>% 
  str_extract("[0-9]+")

last_n_page
[1] "813"

2 Loop for read all thesis

2.1 Read html of each thesis

read_html_thesis <- vector("list", nrow(complete_href_dina))

for (i in seq_len(nrow(complete_href_dina))) {
  if (!(complete_href_dina$tesis_url[i] %in% names(read_html_thesis))) {
    cat(paste("Doing thesis number", i, "..."))
    ok <- FALSE
    counter <- 0
    while (ok == FALSE & counter <= 20) {
      counter <- counter + 1
      out <- tryCatch(
        expr = {
          complete_href_dina$tesis_url[i] %>% 
            read_html()
        },
        error = function(e) {
          Sys.sleep(2)
          e
        }
      )
      if ("error" %in% class(out)) {
        cat(".")
      } else {
        ok <- TRUE
        cat("Successful!")
      }
    }
    cat("\n")
    read_html_thesis[[i]] <- out
    names(read_html_thesis)[i] <- complete_href_dina$tesis_url[i]
  }
}

2.2 Extract information

This function help to extract information about thesis like title, abstract, etc.

extract_information <- function(html) {
  titulo <- html %>% 
    html_elements(".media-body h1") %>% 
    html_text2() %>% 
    tibble(Titulo = .)
  
  info_ident <- html %>%  
    html_table() %>% 
    magrittr::extract2(1) %>% 
    mutate(X1 = str_remove(X1, ":")) %>% 
    pivot_wider(
      names_from = X1,
      values_from = X2
    ) %>% 
    select(-Materia)
  
  tabla2 <- html %>% 
    html_table() %>% 
    magrittr::extract2(2)
  
  info_topic <- tabla2 %>% 
    filter(X1 == "topic") %>% 
    pivot_wider(
      names_from = X1,
      values_from = X2
    ) %>% 
    rename("Tópicos" = topic)
  
  info_facultad <- tabla2 %>% 
    filter(str_detect(X1, "thesis.degree.")) %>% 
    pivot_wider(
        names_from = X1,
        values_from = X2
      )
  
  resumen <- tabla2 %>% 
    filter(X1 == "description") %>% 
    pivot_wider(
        names_from = X1,
        values_from = X2
      ) %>% 
    rename(Resumen = description)
  
  if (nrow(info_facultad) == 0) {
    information <- bind_cols(
      info_ident,
      info_topic,
      titulo,
      resumen
    ) %>% 
      relocate(Titulo, .before = "Formato")
  } else {
    information <- bind_cols(
      info_ident,
      info_topic,
      info_facultad,
      titulo,
      resumen
    ) %>% 
      relocate(Titulo, .before = "Formato")
    
  }
  
  return(information)
}
thesis_information <- vector("list", length(read_html_thesis))

for (i in seq_len(length(read_html_thesis))) {
  thesis_information[[i]] <- extract_information(read_html_thesis[[i]])
  print(i)
}

Join full information about the thesis

thesis_information <- bind_rows(thesis_information) 

thesis_information

2.3 Remove duplicates

The table has 16257 at the moment.

thesis_semifinal <- thesis_information %>% 
  mutate(
    titulo_tmp = str_to_upper(Titulo)
  ) %>%
  distinct(titulo_tmp, .keep_all = TRUE) %>% 
  select(-c(titulo_tmp))

Now, it has 2180.

2.4 Keep with only some universities

list_universidades <- readxl::read_excel("Lista_universidades.xlsx")

thesis_semifinal <- thesis_semifinal %>% 
  filter(Institución %in% list_universidades$Universidades) 

2.5 Filter by discipline

thesis_final <- thesis_semifinal %>% 
  filter(str_detect(thesis.degree.discipline.none.fl_str_mv, 
                    "(Psico|Psicól|Salud|ociales)") &
         !str_detect(thesis.degree.discipline.none.fl_str_mv, 
                     "(Psicomo|Desigualdades|Psiquiatr|Enfermer|Gerencia|Gesti|Doctorado)") |
           is.na(thesis.degree.discipline.none.fl_str_mv))  %>% 
  filter(!str_detect(thesis.degree.name.none.fl_str_mv, 
                     "(Econom|Obstetri|Gesti|Licenciado en Educaci|Nutrici|nutrici|Administrac|ADMINISTRAC|Maestr|Segunda Especialidad|Médico Cirujano|Licenciados en Educación|Licenciada en Educaci|Tecnología M|Contador|Ingeniero|Ingeniería)") |
           is.na(thesis.degree.name.none.fl_str_mv)) %>% 
  filter(!thesis.degree.name.none.fl_str_mv %in% c("Bachiller en educación",
                                                   "ARQUITECTO",
                                                   "Licenciado en Ciencias de la Comunicación",
                                                   "Químico Farmacéutico")) %>% 
  filter(!str_detect(thesis.degree.level.none.fl_str_mv,
                     "(Título de segunda especialidad|Farmacia|Tecnología M|Enfermer)") |
           is.na(thesis.degree.level.none.fl_str_mv)) %>% 
  filter(!str_detect(thesis.degree.grantor.none.fl_str_mv,
                     "(Posgrado|Maestría|Maestria)") |
           is.na(thesis.degree.grantor.none.fl_str_mv)) 

2.6 Separate topics

thesis_final %>% 
  mutate(
    count_n = str_count(Tópicos, "\\R+")
  ) %>% 
  count(count_n) %>% 
  pull(count_n) %>% 
  last()
[1] 14
paste0("Topico_", seq(1:14))
 [1] "Topico_1"  "Topico_2"  "Topico_3"  "Topico_4"  "Topico_5"  "Topico_6"  "Topico_7" 
 [8] "Topico_8"  "Topico_9"  "Topico_10" "Topico_11" "Topico_12" "Topico_13" "Topico_14"
thesis_final <- thesis_final %>% 
  separate("Tópicos", into = all_of(into_string), sep = "\n") %>%
  mutate(
    across(Topico_1:Topico_14, str_squish)
  ) 
Warning: Expected 14 pieces. Additional pieces discarded in 2 rows [686, 1188].
Warning: Expected 14 pieces. Missing pieces filled with `NA` in 2177 rows [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].

2.7 Last format

3 Export to XLSX

openxlsx::write.xlsx(thesis_final,
                     "Table complet thesis psychometric.xlsx")
LS0tCnRpdGxlOiAiSS4gV2ViIFNjcmFwcGluZyBvZiBESU5BIC0gQ29uY3l0ZWMiCmF1dGhvcjogIkJyaWFuIE4uIFBlw7FhLUNhbGVybyIKZGF0ZTogIjIzLzUvMjAyMSIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGhpZ2hsaWdodDoga2F0ZQogICAgdGhlbWU6IGZsYXRseQplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCiMgRmlyc3Qgc3RlcAoKVGhlIFtBTElDSUEgLSBDb25jeXRlYyBwYWdlXShodHRwczovL2FsaWNpYS5jb25jeXRlYy5nb2IucGUpIHdhcyB1c2VkIHRvIHNlYXJjaCBmb3IgdW5kZXJncmFkdWF0ZSB0aGVzZXMgd2l0aCB0aGUgZm9sbG93aW5nIHNlYXJjaCBzdHJhdGVneToKCj4gKCJBbsOhbGlzaXMgRmFjdG9yaWFsIiBPUiAiQW7DoWxpc2lzIGRlIENvbXBvbmVudGVzIFByaW5jaXBhbGVzIiBPUiAiQUNQIiBPUiAiY29uZmlhYmlsaWRhZCIgT1IgImZpYWJpbGlkYWQiIE9SICJhbsOhbGlzaXMgcHNpY29tw6l0cmljbyIgT1IgImJhcmVtYWNpw7NuIikgT1IgKCgidmFsaWRleiIgT1IgInZhbGlkYWNpw7NuIiBPUiAiYWRhcHRhY2nDs24iIE9SICJjb25zdHJ1Y2Npw7NuIiBPUiAiZXN0YW5kYXJpemFjacOzbiIpIEFORCAoImVzY2FsYSIgT1IgImJhdGVyw61hIGRlIHBydWViYXMiIE9SICJwcnVlYmEgcHNpY29sw7NnaWNhIiBPUiAiaW5zdHJ1bWVudG8iIE9SICJjdWVzdGlvbmFyaW8iIE9SICJ0ZXN0IikpCgpJbiBhZGRpdGlvbiwgdGhlIGZvbGxvd2luZyBmaWx0ZXJzIHdlcmUgdXNlZDoKCi0gWWVhciBmcm9tIDIwMTEgdG8gMjAyMAotIFVuZGVyZ3JhZHVhdGUgdGhlc2lzCi0gT3BlbiBBY2Nlc3MgdGhlc2lzCgpBbGwgdGhpcyBpcyBrZXB0IGluIGEgc3RhdGljIGxpbmsgdGhhdCB3aWxsIGJlIHVzZWQgdG8gaW5zcGVjdCBhbmQgc3RvcmUgdGhlIGRhdGEgaW4gYW4gZXhjZWwgZmlsZS4KCmBgYHtyfQpsaWJyYXJ5KHJ2ZXN0KQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCnVybCA8LSAiaHR0cHM6Ly9hbGljaWEuY29uY3l0ZWMuZ29iLnBlL3Z1ZmluZC9TZWFyY2gvUmVzdWx0cz9maWx0ZXIlNUIlNUQ9Zm9ybWF0JTNBJTIyYmFjaGVsb3JUaGVzaXMlMjImZmlsdGVyJTVCJTVEPWV1X3JpZ2h0c19zdHJfbXYlM0ElMjJvcGVuQWNjZXNzJTIyJmxvb2tmb3I9JTI4JUUyJTgwJTlDQW4lQzMlQTFsaXNpcytGYWN0b3JpYWwlRTIlODAlOUQrT1IrJUUyJTgwJTlDQW4lQzMlQTFsaXNpcytkZStDb21wb25lbnRlcytQcmluY2lwYWxlcyVFMiU4MCU5RCtPUislRTIlODAlOUNBQ1AlRTIlODAlOUQrT1IrJUUyJTgwJTlDY29uZmlhYmlsaWRhZCVFMiU4MCU5RCtPUislRTIlODAlOUNmaWFiaWxpZGFkJUUyJTgwJTlEK09SKyVFMiU4MCU5Q2FuJUMzJUExbGlzaXMrcHNpY29tJUMzJUE5dHJpY28lRTIlODAlOUQrT1IrJTIyYmFyZW1hY2klQzMlQjNuJTIyJTI5K09SKyUyOCUyOCVFMiU4MCU5Q3ZhbGlkZXolRTIlODAlOUQrT1IrJTIydmFsaWRhY2klQzMlQjNuJTIyK09SKyUyMmFkYXB0YWNpJUMzJUIzbiUyMitPUislMjJjb25zdHJ1Y2NpJUMzJUIzbiUyMitPUislMjJlc3RhbmRhcml6YWNpJUMzJUIzbiUyMiUyOStBTkQrJTI4JTIyZXNjYWxhJTIyK09SKyVFMiU4MCU5Q2JhdGVyJUMzJUFEYStkZStwcnVlYmFzJUUyJTgwJTlEK09SKyVFMiU4MCU5Q3BydWViYStwc2ljb2wlQzMlQjNnaWNhJUUyJTgwJTlEK09SKyUyMmluc3RydW1lbnRvJTIyK09SKyUyMmN1ZXN0aW9uYXJpbyUyMitPUislMjJ0ZXN0JTIyJTI5JTI5JnR5cGU9QWxsRmllbGRzJmRhdGVyYW5nZSU1QiU1RD1wdWJsaXNoRGF0ZSZwdWJsaXNoRGF0ZWZyb209MjAxMSZwdWJsaXNoRGF0ZXRvPTIwMjAiCgpkaW5hX2h0bWwgPC0gcmVhZF9odG1sKHVybCkgCmBgYAoKIyMgRGV0ZXJtaW5hdGUgdGhlIG51bWJlciBvZiBwYWdlcwoKCmBgYHtyfQpsYXN0X25fcGFnZSA8LSBkaW5hX2h0bWwgJT4lIAogIGh0bWxfZWxlbWVudHMoIi5wYWdpbmF0aW9uIGxpOmxhc3QtY2hpbGQiKSAlPiUgCiAgaHRtbF90ZXh0MigpICU+JSAKICBzdHJfZXh0cmFjdCgiWzAtOV0rIikKCmxhc3Rfbl9wYWdlCmBgYAoKIyMgTG9vcCBmb3IgZXh0cmFjdCBsaW5rcyBpbiBldmVyeSBwYWdlcyBhdmFpYmxlCgpgYGB7cn0KaHJlZl9kaW5hIDwtIHZlY3RvcigibGlzdCIsIGxhc3Rfbl9wYWdlKQoKZm9yIChpIGluIHNlcV9sZW4obGFzdF9uX3BhZ2UpKSB7CiAgaWYgKCEocGFzdGUwKCJwYWdlPSIsIGkpICVpbiUgbmFtZXMoaHJlZl9kaW5hKSkpIHsKICAgIGNhdChwYXN0ZSgiR2V0dGluZyB1cmwgbnVtYmVyIiwgaSwgIi4uLiIpKQogICAgb2sgPC0gRkFMU0UKICAgIGNvdW50ZXIgPC0gMAogICAgd2hpbGUgKG9rID09IEZBTFNFICYgY291bnRlciA8PSAyMCkgewogICAgICBjb3VudGVyIDwtIGNvdW50ZXIgKyAxCiAgICAgIG91dCA8LSB0cnlDYXRjaCgKICAgICAgICBleHByID0gewogICAgICAgICAgcGFzdGUwKHVybCwgIiZwYWdlPSIsIGkpICU+JQogICAgICAgICAgICByZWFkX2h0bWwoKSAlPiUKICAgICAgICAgICAgaHRtbF9lbGVtZW50cygiLnJlc3VsdCAucm93IC5saW5rIGEiKSAlPiUKICAgICAgICAgICAgaHRtbF9hdHRycygpICU+JQogICAgICAgICAgICB1bmxpc3QoKSAlPiUKICAgICAgICAgICAgYXNfdGliYmxlKCkKICAgICAgICB9LAogICAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgewogICAgICAgICAgU3lzLnNsZWVwKDIpCiAgICAgICAgICBlCiAgICAgICAgfQogICAgICApCiAgICAgIGlmICgiZXJyb3IiICVpbiUgY2xhc3Mob3V0KSkgewogICAgICAgIGNhdCgiUmV0cnlpbmcuLi4iKQogICAgICB9IGVsc2UgewogICAgICAgIG9rIDwtIFRSVUUKICAgICAgICBjYXQoIlN1Y2Nlc3NmdWwhIikKICAgICAgfQogICAgfQogICAgY2F0KCJcbiIpCiAgICBocmVmX2RpbmFbW2ldXSA8LSBvdXQKICAgIG5hbWVzKGhyZWZfZGluYSlbaV0gPC0gcGFzdGUwKCJwYWdlPSIsIGkpCiAgfQp9CmBgYAoKYGBge3J9CmNvbXBsZXRlX2hyZWZfZGluYSA8LSBocmVmX2RpbmEgJT4lIAogIGJpbmRfcm93cygpICU+JSAKICBtdXRhdGUoCiAgICB0ZXNpc191cmwgPSBwYXN0ZTAoImh0dHBzOi8vYWxpY2lhLmNvbmN5dGVjLmdvYi5wZSIsCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUpCiAgKSAlPiUgCiAgc2VsZWN0KC12YWx1ZSkKCmNvbXBsZXRlX2hyZWZfZGluYSA8LSBjb21wbGV0ZV9ocmVmX2RpbmEgJT4lIAogIG11dGF0ZSh0ZXNpc191cmwgPSBwYXN0ZTAodGVzaXNfdXJsLCAiL0RldGFpbHMjdGFibmF2IikpCmBgYAoKIyBMb29wIGZvciByZWFkIGFsbCB0aGVzaXMgCgojIyBSZWFkIGh0bWwgb2YgZWFjaCB0aGVzaXMKCmBgYHtyfQpyZWFkX2h0bWxfdGhlc2lzIDwtIHZlY3RvcigibGlzdCIsIG5yb3coY29tcGxldGVfaHJlZl9kaW5hKSkKCmZvciAoaSBpbiBzZXFfbGVuKG5yb3coY29tcGxldGVfaHJlZl9kaW5hKSkpIHsKICBpZiAoIShjb21wbGV0ZV9ocmVmX2RpbmEkdGVzaXNfdXJsW2ldICVpbiUgbmFtZXMocmVhZF9odG1sX3RoZXNpcykpKSB7CiAgICBjYXQocGFzdGUoIkRvaW5nIHRoZXNpcyBudW1iZXIiLCBpLCAiLi4uIikpCiAgICBvayA8LSBGQUxTRQogICAgY291bnRlciA8LSAwCiAgICB3aGlsZSAob2sgPT0gRkFMU0UgJiBjb3VudGVyIDw9IDIwKSB7CiAgICAgIGNvdW50ZXIgPC0gY291bnRlciArIDEKICAgICAgb3V0IDwtIHRyeUNhdGNoKAogICAgICAgIGV4cHIgPSB7CiAgICAgICAgICBjb21wbGV0ZV9ocmVmX2RpbmEkdGVzaXNfdXJsW2ldICU+JSAKICAgICAgICAgICAgcmVhZF9odG1sKCkKICAgICAgICB9LAogICAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgewogICAgICAgICAgU3lzLnNsZWVwKDIpCiAgICAgICAgICBlCiAgICAgICAgfQogICAgICApCiAgICAgIGlmICgiZXJyb3IiICVpbiUgY2xhc3Mob3V0KSkgewogICAgICAgIGNhdCgiLiIpCiAgICAgIH0gZWxzZSB7CiAgICAgICAgb2sgPC0gVFJVRQogICAgICAgIGNhdCgiU3VjY2Vzc2Z1bCEiKQogICAgICB9CiAgICB9CiAgICBjYXQoIlxuIikKICAgIHJlYWRfaHRtbF90aGVzaXNbW2ldXSA8LSBvdXQKICAgIG5hbWVzKHJlYWRfaHRtbF90aGVzaXMpW2ldIDwtIGNvbXBsZXRlX2hyZWZfZGluYSR0ZXNpc191cmxbaV0KICB9Cn0KYGBgCgoKIyMgRXh0cmFjdCBpbmZvcm1hdGlvbgoKVGhpcyBmdW5jdGlvbiBoZWxwIHRvIGV4dHJhY3QgaW5mb3JtYXRpb24gYWJvdXQgdGhlc2lzIGxpa2UgdGl0bGUsIGFic3RyYWN0LCBldGMuCgpgYGB7cn0KZXh0cmFjdF9pbmZvcm1hdGlvbiA8LSBmdW5jdGlvbihodG1sKSB7CiAgdGl0dWxvIDwtIGh0bWwgJT4lIAogICAgaHRtbF9lbGVtZW50cygiLm1lZGlhLWJvZHkgaDEiKSAlPiUgCiAgICBodG1sX3RleHQyKCkgJT4lIAogICAgdGliYmxlKFRpdHVsbyA9IC4pCiAgCiAgaW5mb19pZGVudCA8LSBodG1sICU+JSAgCiAgICBodG1sX3RhYmxlKCkgJT4lIAogICAgbWFncml0dHI6OmV4dHJhY3QyKDEpICU+JSAKICAgIG11dGF0ZShYMSA9IHN0cl9yZW1vdmUoWDEsICI6IikpICU+JSAKICAgIHBpdm90X3dpZGVyKAogICAgICBuYW1lc19mcm9tID0gWDEsCiAgICAgIHZhbHVlc19mcm9tID0gWDIKICAgICkgJT4lIAogICAgc2VsZWN0KC1NYXRlcmlhKQogIAogIHRhYmxhMiA8LSBodG1sICU+JSAKICAgIGh0bWxfdGFibGUoKSAlPiUgCiAgICBtYWdyaXR0cjo6ZXh0cmFjdDIoMikKICAKICBpbmZvX3RvcGljIDwtIHRhYmxhMiAlPiUgCiAgICBmaWx0ZXIoWDEgPT0gInRvcGljIikgJT4lIAogICAgcGl2b3Rfd2lkZXIoCiAgICAgIG5hbWVzX2Zyb20gPSBYMSwKICAgICAgdmFsdWVzX2Zyb20gPSBYMgogICAgKSAlPiUgCiAgICByZW5hbWUoIlTDs3BpY29zIiA9IHRvcGljKQogIAogIGluZm9fZmFjdWx0YWQgPC0gdGFibGEyICU+JSAKICAgIGZpbHRlcihzdHJfZGV0ZWN0KFgxLCAidGhlc2lzLmRlZ3JlZS4iKSkgJT4lIAogICAgcGl2b3Rfd2lkZXIoCiAgICAgICAgbmFtZXNfZnJvbSA9IFgxLAogICAgICAgIHZhbHVlc19mcm9tID0gWDIKICAgICAgKQogIAogIHJlc3VtZW4gPC0gdGFibGEyICU+JSAKICAgIGZpbHRlcihYMSA9PSAiZGVzY3JpcHRpb24iKSAlPiUgCiAgICBwaXZvdF93aWRlcigKICAgICAgICBuYW1lc19mcm9tID0gWDEsCiAgICAgICAgdmFsdWVzX2Zyb20gPSBYMgogICAgICApICU+JSAKICAgIHJlbmFtZShSZXN1bWVuID0gZGVzY3JpcHRpb24pCiAgCiAgaWYgKG5yb3coaW5mb19mYWN1bHRhZCkgPT0gMCkgewogICAgaW5mb3JtYXRpb24gPC0gYmluZF9jb2xzKAogICAgICBpbmZvX2lkZW50LAogICAgICBpbmZvX3RvcGljLAogICAgICB0aXR1bG8sCiAgICAgIHJlc3VtZW4KICAgICkgJT4lIAogICAgICByZWxvY2F0ZShUaXR1bG8sIC5iZWZvcmUgPSAiRm9ybWF0byIpCiAgfSBlbHNlIHsKICAgIGluZm9ybWF0aW9uIDwtIGJpbmRfY29scygKICAgICAgaW5mb19pZGVudCwKICAgICAgaW5mb190b3BpYywKICAgICAgaW5mb19mYWN1bHRhZCwKICAgICAgdGl0dWxvLAogICAgICByZXN1bWVuCiAgICApICU+JSAKICAgICAgcmVsb2NhdGUoVGl0dWxvLCAuYmVmb3JlID0gIkZvcm1hdG8iKQogICAgCiAgfQogIAogIHJldHVybihpbmZvcm1hdGlvbikKfQpgYGAKCmBgYHtyfQp0aGVzaXNfaW5mb3JtYXRpb24gPC0gdmVjdG9yKCJsaXN0IiwgbGVuZ3RoKHJlYWRfaHRtbF90aGVzaXMpKQoKZm9yIChpIGluIHNlcV9sZW4obGVuZ3RoKHJlYWRfaHRtbF90aGVzaXMpKSkgewogIHRoZXNpc19pbmZvcm1hdGlvbltbaV1dIDwtIGV4dHJhY3RfaW5mb3JtYXRpb24ocmVhZF9odG1sX3RoZXNpc1tbaV1dKQogIHByaW50KGkpCn0KYGBgCgpKb2luIGZ1bGwgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHRoZXNpcwoKYGBge3J9CnRoZXNpc19pbmZvcm1hdGlvbiA8LSBiaW5kX3Jvd3ModGhlc2lzX2luZm9ybWF0aW9uKSAKCnRoZXNpc19pbmZvcm1hdGlvbgpgYGAKCiMjIFJlbW92ZSBkdXBsaWNhdGVzCgpUaGUgdGFibGUgaGFzIGByIG5yb3codGhlc2lzX2luZm9ybWF0aW9uKWAgYXQgdGhlIG1vbWVudC4KCmBgYHtyfQp0aGVzaXNfc2VtaWZpbmFsIDwtIHRoZXNpc19pbmZvcm1hdGlvbiAlPiUgCiAgbXV0YXRlKAogICAgdGl0dWxvX3RtcCA9IHN0cl90b191cHBlcihUaXR1bG8pCiAgKSAlPiUKICBkaXN0aW5jdCh0aXR1bG9fdG1wLCAua2VlcF9hbGwgPSBUUlVFKSAlPiUgCiAgc2VsZWN0KC1jKHRpdHVsb190bXApKQpgYGAKCk5vdywgaXQgaGFzIGByIG5yb3codGhlc2lzX2ZpbmFsKWAuCgojIyBLZWVwIHdpdGggb25seSBzb21lIHVuaXZlcnNpdGllcwoKYGBge3J9Cmxpc3RfdW5pdmVyc2lkYWRlcyA8LSByZWFkeGw6OnJlYWRfZXhjZWwoIkxpc3RhX3VuaXZlcnNpZGFkZXMueGxzeCIpCgp0aGVzaXNfc2VtaWZpbmFsIDwtIHRoZXNpc19zZW1pZmluYWwgJT4lIAogIGZpbHRlcihJbnN0aXR1Y2nDs24gJWluJSBsaXN0X3VuaXZlcnNpZGFkZXMkVW5pdmVyc2lkYWRlcykgCmBgYAoKIyMgRmlsdGVyIGJ5IGRpc2NpcGxpbmUKCmBgYHtyfQp0aGVzaXNfZmluYWwgPC0gdGhlc2lzX3NlbWlmaW5hbCAlPiUgCiAgZmlsdGVyKHN0cl9kZXRlY3QodGhlc2lzLmRlZ3JlZS5kaXNjaXBsaW5lLm5vbmUuZmxfc3RyX212LCAKICAgICAgICAgICAgICAgICAgICAiKFBzaWNvfFBzaWPDs2x8U2FsdWR8b2NpYWxlcykiKSAmCiAgICAgICAgICFzdHJfZGV0ZWN0KHRoZXNpcy5kZWdyZWUuZGlzY2lwbGluZS5ub25lLmZsX3N0cl9tdiwgCiAgICAgICAgICAgICAgICAgICAgICIoUHNpY29tb3xEZXNpZ3VhbGRhZGVzfFBzaXF1aWF0cnxFbmZlcm1lcnxHZXJlbmNpYXxHZXN0aXxEb2N0b3JhZG8pIikgfAogICAgICAgICAgIGlzLm5hKHRoZXNpcy5kZWdyZWUuZGlzY2lwbGluZS5ub25lLmZsX3N0cl9tdikpICAlPiUgCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHRoZXNpcy5kZWdyZWUubmFtZS5ub25lLmZsX3N0cl9tdiwgCiAgICAgICAgICAgICAgICAgICAgICIoRWNvbm9tfE9ic3RldHJpfEdlc3RpfExpY2VuY2lhZG8gZW4gRWR1Y2FjaXxOdXRyaWNpfG51dHJpY2l8QWRtaW5pc3RyYWN8QURNSU5JU1RSQUN8TWFlc3RyfFNlZ3VuZGEgRXNwZWNpYWxpZGFkfE3DqWRpY28gQ2lydWphbm98TGljZW5jaWFkb3MgZW4gRWR1Y2FjacOzbnxMaWNlbmNpYWRhIGVuIEVkdWNhY2l8VGVjbm9sb2fDrWEgTXxDb250YWRvcnxJbmdlbmllcm98SW5nZW5pZXLDrWEpIikgfAogICAgICAgICAgIGlzLm5hKHRoZXNpcy5kZWdyZWUubmFtZS5ub25lLmZsX3N0cl9tdikpICU+JSAKICBmaWx0ZXIoIXRoZXNpcy5kZWdyZWUubmFtZS5ub25lLmZsX3N0cl9tdiAlaW4lIGMoIkJhY2hpbGxlciBlbiBlZHVjYWNpw7NuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFSUVVJVEVDVE8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTGljZW5jaWFkbyBlbiBDaWVuY2lhcyBkZSBsYSBDb211bmljYWNpw7NuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlF1w61taWNvIEZhcm1hY8OpdXRpY28iKSkgJT4lIAogIGZpbHRlcighc3RyX2RldGVjdCh0aGVzaXMuZGVncmVlLmxldmVsLm5vbmUuZmxfc3RyX212LAogICAgICAgICAgICAgICAgICAgICAiKFTDrXR1bG8gZGUgc2VndW5kYSBlc3BlY2lhbGlkYWR8RmFybWFjaWF8VGVjbm9sb2fDrWEgTXxFbmZlcm1lcikiKSB8CiAgICAgICAgICAgaXMubmEodGhlc2lzLmRlZ3JlZS5sZXZlbC5ub25lLmZsX3N0cl9tdikpICU+JSAKICBmaWx0ZXIoIXN0cl9kZXRlY3QodGhlc2lzLmRlZ3JlZS5ncmFudG9yLm5vbmUuZmxfc3RyX212LAogICAgICAgICAgICAgICAgICAgICAiKFBvc2dyYWRvfE1hZXN0csOtYXxNYWVzdHJpYSkiKSB8CiAgICAgICAgICAgaXMubmEodGhlc2lzLmRlZ3JlZS5ncmFudG9yLm5vbmUuZmxfc3RyX212KSkgCmBgYAoKCiMjIFNlcGFyYXRlIHRvcGljcwoKCgpgYGB7cn0Kbl9kaWZmZXJlbnRzX3RvcGljIDwtIHRoZXNpc19maW5hbCAlPiUgCiAgbXV0YXRlKAogICAgY291bnRfbiA9IHN0cl9jb3VudChUw7NwaWNvcywgIlxcUisiKQogICkgJT4lIAogIGNvdW50KGNvdW50X24pICU+JSAKICBwdWxsKGNvdW50X24pICU+JSAKICBsYXN0KCkKYGBgCgpgYGB7cn0KaW50b19zdHJpbmcgPC0gcGFzdGUwKCJUb3BpY29fIiwgc2VxKDE6MTQpKQpgYGAKCmBgYHtyfQp0aGVzaXNfZmluYWwgPC0gdGhlc2lzX2ZpbmFsICU+JSAKICBzZXBhcmF0ZSgiVMOzcGljb3MiLCBpbnRvID0gYWxsX29mKGludG9fc3RyaW5nKSwgc2VwID0gIlxuIikgJT4lCiAgbXV0YXRlKAogICAgYWNyb3NzKFRvcGljb18xOlRvcGljb18xNCwgc3RyX3NxdWlzaCkKICApIApgYGAKCiMjIExhc3QgZm9ybWF0CgpgYGB7cn0KdGhlc2lzX2ZpbmFsIDwtIHRoZXNpc19maW5hbCAlPiUgCiAgbXV0YXRlKElEID0gMTpucm93KC4pKSAlPiUgCiAgcmVsb2NhdGUoSUQsIC5iZWZvcmUgPSBgQXV0b3IgUHJpbmNpcGFsYCkgJT4lIAogIHJlbG9jYXRlKGBPdHJvcyBBdXRvcmVzYCwgLmFmdGVyID0gYEF1dG9yIFByaW5jaXBhbGApICU+JSAKICByZWxvY2F0ZSh0aGVzaXMuZGVncmVlLnByb2dyYW0ubm9uZS5mbF9zdHJfbXYsIC5iZWZvcmUgPSBSZXN1bWVuKQogIAoKdGhlc2lzX2ZpbmFsCmBgYAoKIyBFeHBvcnQgdG8gWExTWAoKYGBge3J9Cm9wZW54bHN4Ojp3cml0ZS54bHN4KHRoZXNpc19maW5hbCwKICAgICAgICAgICAgICAgICAgICAgIlRhYmxlIGNvbXBsZXQgdGhlc2lzIHBzeWNob21ldHJpYy54bHN4IikKYGBgCg==